#include "eeprom.h"
#include <intrins.h>
#include "STC8H.H"

#define fosc 11059200  // System frequency (STC8H default is 11.0592MHz)
// EEPROM Page size (typical for STC8H)
#define EEPROM_PAGE_SIZE 512 //弃用，使用时将EEPROM_BUFFER_SIZE 宏定义为EEPROM_PAGE_SIZE
#define EEPROM_BUFFER_SIZE 6
// IAP commands
#define CMD_IDLE    0x00
#define CMD_READ    0x01
#define CMD_WRITE   0x02
#define CMD_ERASE   0x03

// Wait time
#define WAIT_TIME   0x01
// Temporary buffer for page operations
static uint8_t page_buffer[EEPROM_BUFFER_SIZE];

static void EEPROM_WritePage(uint16_t page_addr, uint8_t* buffer)
{
    uint16_t i;
    
    // Erase the page first
    EEPROM_EraseSector(page_addr);
    
    // Write the entire page
    for(i = 0; i < EEPROM_PAGE_SIZE; i++)
    {
        EEPROM_WriteByte(page_addr + i, buffer[i]);
    }
}

static void EEPROM_ReadPage(uint16_t page_addr, uint8_t* buffer)
{
    uint16_t i;
    for(i = 0; i < EEPROM_PAGE_SIZE; i++)
    {
        buffer[i] = EEPROM_ReadByte(page_addr + i);
    }
}

void EEPROM_SafeWriteByte(uint16_t addr, uint8_t _dat)
{
    uint16_t page_start = addr & ~(EEPROM_PAGE_SIZE - 1);
    uint16_t page_offset = addr & (EEPROM_PAGE_SIZE - 1);
    
    // Read the entire page
    EEPROM_ReadPage(page_start, page_buffer);
    
    // Modify the byte
    page_buffer[page_offset] = _dat;
    
    // Write back the entire page
    EEPROM_WritePage(page_start, page_buffer);
}
void EEPROM_SafeWriteUint16(uint16_t addr, uint16_t _dat)
{
    uint16_t page_start = addr & ~(EEPROM_PAGE_SIZE - 1);
    uint16_t page_offset = addr & (EEPROM_PAGE_SIZE - 1);

    if (page_offset > EEPROM_PAGE_SIZE - sizeof(uint16_t))
        return;  // Cannot safely write across page boundary

    EEPROM_ReadPage(page_start, page_buffer);
    page_buffer[page_offset] = (uint8_t)(_dat & 0xFF);
    page_buffer[page_offset + 1] = (uint8_t)((_dat >> 8) & 0xFF);
    EEPROM_WritePage(page_start, page_buffer);
}




static void EEPROM_Wait(void)
{
    uint8_t i = WAIT_TIME;
    while(i--);
}

void EEPROM_Init(void)
{
    IAP_CONTR = 0x80;  // Enable IAP
    IAP_TPS=fosc/1000000;                     //设置等待参数33mhz
    IAP_CMD = CMD_IDLE;
    IAP_TRIG = 0x00;
}

void EEPROM_Idle(void)
{
    IAP_CONTR = 0x00;  // Disable IAP
    IAP_CMD = CMD_IDLE;
    IAP_TRIG = 0x00;
}

uint8_t EEPROM_ReadByte(uint16_t addr)
{
    uint8_t _dat;
    EEPROM_Init();
    IAP_ADDRH = (uint8_t)(addr >> 8);
    IAP_ADDRL = (uint8_t)(addr & 0xFF);
    IAP_CMD = CMD_READ;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    EEPROM_Wait();
    _dat = IAP_DATA;
    EEPROM_Idle();
    
    return _dat;
}

void EEPROM_WriteByte(uint16_t addr, uint8_t _dat)
{
    EEPROM_Init();
    IAP_ADDRH = (uint8_t)(addr >> 8);
    IAP_ADDRL = (uint8_t)(addr & 0xFF);
    IAP_DATA = _dat;
    IAP_CMD = CMD_WRITE;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    EEPROM_Wait();
    EEPROM_Idle();
}

void EEPROM_EraseSector(uint16_t addr)
{
    EEPROM_Init();
    IAP_ADDRH = (uint8_t)(addr >> 8);
    IAP_ADDRL = (uint8_t)(addr & 0xFF);
    IAP_CMD = CMD_ERASE;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    EEPROM_Wait();
    EEPROM_Idle();
}

// Utility functions for different _dat types
void EEPROM_WriteInt16(uint16_t addr, int16_t _dat)
{
    EEPROM_WriteByte(addr, (uint8_t)(_dat & 0xFF));
    EEPROM_WriteByte(addr + 1, (uint8_t)(_dat >> 8));
}

int16_t EEPROM_ReadInt16(uint16_t addr)
{
    int16_t _dat;
    _dat = EEPROM_ReadByte(addr);
    _dat |= ((int16_t)EEPROM_ReadByte(addr + 1)) << 8;
    return _dat;
}

void EEPROM_WriteFloat(uint16_t addr, float _dat)
{
    uint8_t* ptr = (uint8_t*)&_dat;
    uint8_t i;
    for(i = 0; i < sizeof(float); i++)
    {
        EEPROM_WriteByte(addr + i, ptr[i]);
    }
}

float EEPROM_ReadFloat(uint16_t addr)
{
    float _dat;
    uint8_t* ptr = (uint8_t*)&_dat;
    uint8_t i;
    for(i = 0; i < sizeof(float); i++)
    {
        ptr[i] = EEPROM_ReadByte(addr + i);
    }
    return _dat;
}
uint16_t EEPROM_ReadUint16(uint16_t addr)
{
    uint16_t _dat;
    _dat = EEPROM_ReadByte(addr);
    _dat |= ((uint16_t)EEPROM_ReadByte(addr + 1)) << 8;
    return _dat;
}